package business.global.pk.ddz;

import business.ddz.c2s.cclass.DDZ_define;
import business.ddz.c2s.cclass.DDZ_define.DDZ_CARD_TYPE;
import business.ddz.c2s.iclass.CDDZ_OpCard;
import business.ddz.c2s.iclass.SDDZ_OpCard;
import business.global.pk.alg.params.BaseOpCard;
import business.global.pk.alg.params.BasePKParameter;
import business.global.pk.alg.BasePkCardTypeFactory;
import business.global.pk.alg.type.*;
import business.global.pk.ddz.cardtype.RobotInfo;
import business.global.pk.ddz.cardtype.type.*;
import business.player.Robot.RobotMgr;
import com.ddm.server.common.utils.CommTime;
import com.ddm.server.websocket.def.ErrorCode;
import com.ddm.server.websocket.handler.requset.WebSocketRequest;
import com.ddm.server.websocket.handler.requset.WebSocketRequestDelegate;
import jsproto.c2s.cclass.pk.BasePocker;
import jsproto.c2s.cclass.pk.BasePockerLogic;
import org.apache.commons.collections.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 斗地主一回合游戏逻辑
 *
 * @author zaf
 */
public class DDZRoomSetRound {

    public DDZRoom room;
    public DDZRoomSet set;
    public int currentOpPos; //本回合等待操作玩家
    public int lastOpPos = -1;//本回合上轮最后打牌玩家
    public int lastOpCardType = DDZ_CARD_TYPE.DDZ_CARD_TYPE_NOMARL.value();  //本回合上轮最后打牌的类型
    public ArrayList<Integer> lastCardList = new ArrayList<>(); //本回合上轮最后打出的牌
    public boolean turnEnd = false; //回合结束
    public boolean m_bSetEnd = false; //是否局结束
    public int firstOpPos; //首出玩家
    private static final int INTERVAL = 30000;//托管时间间隔
    private static final int JOKERVALUE = 18;//炸弹的值
    //上回和操作
    private BaseOpCard lastBaseOpCard = new BaseOpCard();

    public DDZRoomSetRound(DDZRoomSet set) {
        this.set = set;
        this.room = set.room;
        this.currentOpPos = set.getOpPos();
        this.firstOpPos = set.getOpPos();
    }

    public void clean() {
        this.room = null;
        this.set = null;
        this.lastCardList = null;
    }

    /**
     * 更新回合状态
     *
     * @return
     */
    public boolean update() {
        //是否一回合结束或者一局结束
        if (turnEnd || m_bSetEnd) {
            return true;
        }
        if(CommTime.nowMS() - this.set.startMS > 300){
            if(this.room.autoPass()){
                if(this.lastOpCardType != DDZ_CARD_TYPE.DDZ_CARD_TYPE_NOMARL.value()){
                    DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(currentOpPos);
                    //手牌排序
                    ArrayList<Integer> clonePrivateCards = (ArrayList<Integer>) roomPos.privateCards.clone();
                    clonePrivateCards.sort(BasePockerLogic.sorterBigToSmallHaveTrump);
                    List<BaseOpCard> cardTypeList = checkMaxCardList(clonePrivateCards, clonePrivateCards.size(), currentOpPos);
                    //出不了牌
                    if (CollectionUtils.isEmpty(cardTypeList)) {
                        this.onOpCard(new WebSocketRequestDelegate(), CDDZ_OpCard.make(this.room.getRoomID(), currentOpPos, DDZ_CARD_TYPE.DDZ_CARD_TYPE_BUCHU.value(), new ArrayList<>(), 0,true));
                    }
                }
            }
        }
        return false;
    }

    /**
     * 获取所有可能牌型
     *
     * @param parameter     输入参数
     * @param cardType      牌型
     * @param parameterList 牌型列表自
     * @param pos           位置
     */
    public void getCard(BasePKParameter parameter, Class cardType, List<BaseOpCard> parameterList, int pos) {
        ArrayList<Integer> privateCards = parameter.getCloneOpTypeCardList();
        BaseOpCard outCardList = BasePkCardTypeFactory.getCardType(cardType).getCardList(parameter);
        if (outCardList != null) {
            if (cardType == DDZSingle.class) {
                RobotInfo robotInfo = (RobotInfo)parameter.robotInfo;
                if(!robotInfo.isLandowner && robotInfo.partnerRemaining<=1 && !robotInfo.isGenPai){
                    outCardList.cardList = new ArrayList<>(Collections.singletonList(privateCards.get(privateCards.size()-1)));
                    outCardList.compareValue = BasePocker.getCardValueEx(privateCards.get(privateCards.size()-1));
                }else{
                    boolean isNextSingle = this.room.getRoomPosMgr().getPosList().stream().anyMatch(n -> ((DDZRoomPos) n).privateCards.size() == 1 && n.getPosID() != pos);
                    if (isNextSingle) {
                        outCardList.cardList = new ArrayList<>(Collections.singletonList(privateCards.get(0)));
                        outCardList.compareValue = BasePocker.getCardValueEx(privateCards.get(0));
                    }
                }
            }
            parameterList.add(outCardList);
        }
    }

    /**
     * 机器人获取最优牌型
     *
     * @param opTypeCardsList   操作牌型
     * @param remainingCardSize 剩余手牌
     * @param pos               位置
     * @return 最优牌型
     */
    public BaseOpCard robotGetCardType(ArrayList<Integer> opTypeCardsList, int remainingCardSize, int pos) {
        List<BaseOpCard> inputList = new ArrayList<>();
        DDZTypeAdapter.getInstance().getTypeList().stream().forEach(classType -> {
            if (prefix(classType)) {
                BasePKParameter parameter = new BasePKParameter();
                parameter.init(lastBaseOpCard.cardList, lastBaseOpCard.opCardType, lastBaseOpCard.compareValue, lastBaseOpCard.tripleNum, opTypeCardsList,new ArrayList<>(), remainingCardSize);
                initRobotInfo(parameter, pos);
                getCard(parameter, classType, inputList, pos);
            }
        });
        List<BaseOpCard> parameterList = inputList;
        Optional<BaseOpCard> first = parameterList.stream().filter(n -> n.opCardType == DDZ_CARD_TYPE.DDZ_CARD_TYPE_SINGLECARD.value()).findFirst();
        if(first.isPresent()){
            int cardValueEx = BasePocker.getCardValueEx(first.get().cardList.get(0));
            boolean b = parameterList.stream().anyMatch(n -> n.opCardType != DDZ_CARD_TYPE.DDZ_CARD_TYPE_SINGLECARD.value() && n.cardList.stream().anyMatch(p -> BasePocker.getCardValueEx(p) == cardValueEx));
            if(b){
                parameterList = parameterList.stream().filter(n -> n.opCardType != DDZ_CARD_TYPE.DDZ_CARD_TYPE_SINGLECARD.value()).collect(Collectors.toList());
            }
        }
        Optional<BaseOpCard> second = parameterList.stream().filter(n -> n.opCardType == DDZ_CARD_TYPE.DDZ_CARD_TYPE_DUIZI.value()).findFirst();
        if(second.isPresent()){
            int cardValueEx = BasePocker.getCardValueEx(second.get().cardList.get(0));
            boolean b = parameterList.stream().anyMatch(n -> n.opCardType != DDZ_CARD_TYPE.DDZ_CARD_TYPE_DUIZI.value() && n.cardList.stream().filter(p->BasePocker.getCardValueEx(p)==cardValueEx).count() >=2);
            if(b){
                parameterList = parameterList.stream().filter(n -> n.opCardType != DDZ_CARD_TYPE.DDZ_CARD_TYPE_DUIZI.value()).collect(Collectors.toList());
            }
        }
        BasePKParameter parameter = new BasePKParameter();
        parameter.init(lastBaseOpCard.cardList, lastBaseOpCard.opCardType, lastBaseOpCard.compareValue, lastBaseOpCard.tripleNum, opTypeCardsList,new ArrayList<>(), remainingCardSize);
        initRobotInfo(parameter, pos);
        if (parameterList.size() > 0) {
            int totalWeight = parameterList.stream().mapToInt(n -> TypeWeight.getWeight(n, remainingCardSize)).sum();
            List<BaseOpCard> sortList = parameterList.stream().sorted((o1, o2) -> {
                if (o1.weight > o2.weight) {
                    return -1;
                }
                return 1;
            }).collect(Collectors.toList());
            List<BaseOpCard> opCardList = new ArrayList<>();
            List<Integer> chanceList = new ArrayList<>();
            sortList.stream().forEach(n -> {opCardList.add(n);chanceList.add(n.weight);});
            if(sortList.get(0).weight > TypeWeight.maxWeight){//能出完直接出
                return sortList.get(0);
            }else{
                RobotInfo robotInfo = (RobotInfo)parameter.robotInfo;
                if(!robotInfo.isLandowner && robotInfo.isGenPai && robotInfo.lastIsPartner){
                    if(lastOpCardType != DDZ_CARD_TYPE.DDZ_CARD_TYPE_SINGLECARD.value() && lastOpCardType != DDZ_CARD_TYPE.DDZ_CARD_TYPE_DUIZI.value()){
                        return new BaseOpCard();
                    }else{
                        if(robotInfo.partnerRemaining<=3){
                            return new BaseOpCard();
                        }
                    }
                }
                return TypeWeight.getRandomCard(totalWeight, opCardList,chanceList);
            }
        }
        return new BaseOpCard();
    }

    /**
     * 检验是否有大于他的牌
     *
     * @param opTypeCardsList   操作牌型
     * @param remainingCardSize 剩余手牌
     * @param pos               位置
     * @return 最优牌型
     */
    public List<BaseOpCard> checkMaxCardList(ArrayList<Integer> opTypeCardsList, int remainingCardSize, int pos) {
        List<BaseOpCard> inputList = new ArrayList<>();
        DDZTypeAdapter.getInstance().getTypeList().stream().forEach(classType -> {
            if (prefix(classType)) {
                BasePKParameter parameter = new BasePKParameter();
                parameter.init(lastBaseOpCard.cardList, lastBaseOpCard.opCardType, lastBaseOpCard.compareValue, lastBaseOpCard.tripleNum, opTypeCardsList,new ArrayList<>(), remainingCardSize);
                initRobotInfo(parameter, pos);
                getCard(parameter, classType, inputList, pos);
            }
        });
        return inputList;
    }

    /**
     * 初始化机器人记忆信息
     *
     * @param parameter
     * @param pos
     */
    private void initRobotInfo(BasePKParameter parameter, int pos) {
        RobotInfo robotInfo = new RobotInfo();
        robotInfo.isGenPai = (lastOpCardType != DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_NOMARL.value());
        robotInfo.isLandowner = (set.landowner == pos);
        DDZRoomPos selfPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(pos);
        robotInfo.selfRemaining = selfPos.privateCards.size();
        if (!robotInfo.isLandowner) {
            robotInfo.lastIsPartner = (lastOpPos != set.landowner);
            Integer partnerPosID = Stream.of(0, 1, 2).filter(n -> n != pos && n != set.landowner).findFirst().orElse(pos);
            DDZRoomPos partnerPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(partnerPosID);
            robotInfo.partnerRemaining = partnerPos.privateCards.size();
            robotInfo.partnerIsNext = ((pos + 1) % this.room.getPlayerNum() != set.landowner);
            DDZRoomPos landownerPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(set.landowner);
            robotInfo.rivalRemaining = landownerPos.privateCards.size();
        } else {
            //对手剩余的手牌
            List<Integer> cardList = new ArrayList<>();
            DDZRoomPos pos1 = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(((pos + 1) % this.room.getPlayerNum()));
            DDZRoomPos pos2 = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(((pos + 2) % this.room.getPlayerNum()));
            cardList.add(pos1.privateCards.size());
            cardList.add(pos2.privateCards.size());
            robotInfo.rivalRemainingList = cardList;
        }
        parameter.robotInfo = robotInfo;
    }

    /**
     * 前置判断
     *
     * @param classType
     * @return
     */
    private boolean prefix(Class classType) {
        if (classType == DDZPlaneWithPairs.class) {
            return this.room.isThreeZoneWithPairs();
        }
        if (classType == DDZPlaneWithA.class) {
            return this.room.isThreeZoneWithA();
        }
        if (classType == DDZFourWithTwoPairs.class) {
            return this.room.isFourWithTwoPairs();
        }
        if (classType == DDZFourWithTwo.class) {
            return this.room.isFourWithTwo();
        }
        if (classType == DDZFourWithAPairs.class) {
            return this.room.isFourWithAPairs();
        }
        if (classType == DDZFourWithA.class) {
            return this.room.isFourWithA();
        }
        if (classType == DDZThreeZoneWithPairs.class) {
            return this.room.isThreeZoneWithPairs();
        }
        if (classType == DDZThreeZoneWithA.class) {
            return this.room.isThreeZoneWithA();
        }
        return true;
    }

    /**
     * 机器人托管
     *
     * @param pos
     */
    public void roomTrusteeship(int pos) {
        //不是金币房或者玩家已经赢了，或者不是你的回合，抛弃掉
        if (this.checkEndSet() || this.currentOpPos != pos) {
            return;
        }
        if (CommTime.nowMS() - this.set.startMS <= 100) {
            return;
        }
        DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(pos);
        //手牌排序
        ArrayList<Integer> clonePrivateCards = (ArrayList<Integer>) roomPos.privateCards.clone();
        clonePrivateCards.sort(BasePockerLogic.sorterBigToSmallHaveTrump);
        //机器人智能获取最优牌型
        BaseOpCard cardType = robotGetCardType(clonePrivateCards, clonePrivateCards.size(), pos);
        List<Integer> outCardList = cardType.cardList;
        //带牌有王炸的直接打王炸组合
        List<Integer> cardList = outCardList.stream().filter(n -> BasePocker.getCardValueExx(n) == JOKERVALUE).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(cardList) && cardList.size() >= 2) {
            cardType.opCardType = DDZ_CARD_TYPE.DDZ_CARD_TYPE_ZHADAN.value();
            cardType.cardList = cardList;
            cardType.daiNum = 0;
        }
        //出不了牌，机器人
        if (CollectionUtils.isEmpty(outCardList)) {
            cardType.opCardType = DDZ_CARD_TYPE.DDZ_CARD_TYPE_BUCHU.value();
            cardType.daiNum = 0;
        }
        WebSocketRequest request = new WebSocketRequestDelegate();
        boolean flag = this.onOpCard(request, CDDZ_OpCard.make(this.room.getRoomID(), pos, cardType.opCardType, (ArrayList<Integer>) outCardList, cardType.daiNum,true));
        if (!flag) {
            if (CommTime.nowMS() - this.set.startMS > INTERVAL) {//出不了牌就不出
                cardType.opCardType = DDZ_CARD_TYPE.DDZ_CARD_TYPE_BUCHU.value();
                cardType.daiNum = 0;
                cardType.cardList.clear();
                flag = this.onOpCard(request, CDDZ_OpCard.make(this.room.getRoomID(), pos, cardType.opCardType, (ArrayList<Integer>) cardType.cardList, cardType.daiNum,true));
                if (!flag) { //还是不行就流局
                    if (roomPos.getPid() > RobotMgr.getInstance().limitID && RobotMgr.getInstance().isRobot((int) roomPos.getPid())) {
                        this.set.endSet();
                    }
                }
                return;
            }
        }
    }

    /**
     * 打牌操作
     *
     * @param request 请求
     * @param opCard  操作
     * @return
     */
    public synchronized boolean onOpCard(WebSocketRequest request, CDDZ_OpCard opCard) {
        BaseOpCard baseOpCard = null;
        //回合已结束,不允许再操作，等update更新下一回合
        if (turnEnd) {
            if (null != request) request.error(ErrorCode.NotAllow, "onOpCard error: turnEnd is ture");
            return false;
        }
        //请求操作的玩家是否是当前回合的操作者
        if (opCard.pos != currentOpPos) {
            if (null != request)
                request.error(ErrorCode.NotAllow, "onOpCard error: not current pos op oppos: " + currentOpPos);
            return false;
        }
        DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(opCard.pos);

        //校验牌是否是自己的
        if (DDZ_CARD_TYPE.DDZ_CARD_TYPE_BUCHU.value() != opCard.opCardType && !this.checkIsMyCard(opCard)) {//牌不是自己的
            if (null != request) request.error(ErrorCode.NotAllow, "onOpCard error:card is not myself");
            return false;
        }

        //操作结束
        if (DDZ_CARD_TYPE.DDZ_CARD_TYPE_BUCHU.value() == opCard.opCardType) {
            if (lastOpCardType == DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_NOMARL.value()) { //回合首回合必出
                if (null != request) request.error(ErrorCode.NotAllow, "onOpCard error:PDK_WANFA_FEIBICHU");
                return false;
            } else {
                ArrayList<Integer> clonePrivateCards = (ArrayList<Integer>) roomPos.privateCards.clone();
                clonePrivateCards.sort(BasePockerLogic.sorterBigToSmallHaveTrump);
            }
        } else if (DDZ_CARD_TYPE.DDZ_CARD_TYPE_ZHADAN.value() == opCard.opCardType) {
            //校验是否是炸弹，且比上一轮大
            if (this.isBombBigThanLast(opCard.opCardType, opCard.cardList, roomPos.getPrivateCards().size())) {
                baseOpCard = BaseOpCard.make(opCard.opCardType, 0, opCard.cardList);
                baseOpCard.compareValue = BasePocker.getCardValueEx(opCard.cardList.get(0));
                set.roomDouble *= 2;
            } else {
                if (null != request) {
                    //System.out.println("["+opCard.pos+"]操作"+"["+opCard.opCardType+"]"+ sysCardList(opCard.cardList)+""+"：上回合["+lastOpPos+"]操作["+lastOpCardType+"]"+ sysCardList(lastCardList)+"");
                    request.error(ErrorCode.NotAllow, "onOpCard error:card isBombBigThanLast fail");
                }
                return false;
            }
        } else {//不是炸弹类型
            //检验是否是同牌型的互比，带比带，对比对，单张比单张
            if (lastOpCardType != DDZ_CARD_TYPE.DDZ_CARD_TYPE_NOMARL.value() && this.lastOpCardType != opCard.opCardType) {
                if (null != request)
                    request.error(ErrorCode.NotAllow, "onOpCard error:optype do not op,this last opType:" + this.lastOpCardType + ",your optype:" + opCard.opCardType);
                return false;
            }
            ArrayList<Integer> clonePrivateCards = opCard.cardList;
            clonePrivateCards.sort(BasePockerLogic.sorterBigToSmallHaveTrump);
            baseOpCard = this.checkCard(clonePrivateCards, roomPos.privateCards, opCard.pos, opCard.opCardType);
            if (baseOpCard == null) {
                //System.out.println("checkCardList"+"["+opCard.pos+"]操作"+"["+opCard.opCardType+"]"+ sysCardList(opCard.cardList)+"");
                if (null != request) request.error(ErrorCode.NotAllow, "onOpCard error:card check fail");
                return false;
            }
        }

        //删牌
        if (opCard.cardList.size() > 0 && !roomPos.deleteCard(opCard.cardList)) {
            if (null != request)
                request.error(ErrorCode.NotAllow, "card delete error : your cards:" + opCard.cardList.toString() + ", posCard:" + roomPos.getPrivateCards().toString());
            return false;
        }

        //是否是首出
        this.set.setbFirstOp(false);

        if (opCard.opCardType == DDZ_CARD_TYPE.DDZ_CARD_TYPE_BUCHU.value()) {
            //不出，可能会出现过了一圈，每人要的起，新增下一轮操作位
            roomPos.setLatelyOutCardTime(0L);
            this.addOpPos(true);
            //System.out.println("["+opCard.pos+"]操作完毕"+"["+opCard.opCardType+"]"+ sysCardList(opCard.cardList)+"");
        } else {
            //记牌器通知牌剩余
            this.set.setCard.subCardCount(opCard.cardList);
            //记录上一轮信息
            this.lastOpCardType = opCard.opCardType;
            //System.out.println("["+opCard.pos+"]操作完毕"+"["+opCard.opCardType+"]"+ sysCardList(opCard.cardList)+"");
            this.lastOpPos = opCard.pos;
            //记录上一轮操作的牌
            this.lastCardList = opCard.cardList;
            //记录上轮操作
            this.lastBaseOpCard = baseOpCard;
            roomPos.addPublicCard(opCard.cardList);
            roomPos.setLatelyOutCardTime(0L);
            //普通设置下一轮操作者
            this.addOpPos(false);
            //是不是没牌了，结束
            this.checkEndSet();
        }
        //通知打牌
        DDZRoomPosMgr roomPosMgr = (DDZRoomPosMgr) this.room.getRoomPosMgr();
        int opPosCardLength = checkAndReturnLeaveCard(roomPos);
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            ArrayList<Integer> privateList = resolveCardList(roomPos.privateCards, i, roomPos.getPosID());
            if (0 == i) {
                this.set.getRoomPlayBack().playBack2Pos(i, SDDZ_OpCard.make(opCard.roomID, opCard.pos, opCard.opCardType, currentOpPos, opCard.cardList, turnEnd, opCard.daiNum, m_bSetEnd, privateList, this.set.roomDouble, opPosCardLength,opCard.isFlash), roomPosMgr.getAllPlayBackNotify());
            } else {
                this.room.getRoomPosMgr().notify2Pos(i, SDDZ_OpCard.make(opCard.roomID, opCard.pos, opCard.opCardType, currentOpPos, opCard.cardList, turnEnd, opCard.daiNum, m_bSetEnd, privateList, this.set.roomDouble, opPosCardLength,opCard.isFlash));
            }
        }
        return true;
    }

    /**
     * 获取所有可能牌型
     *
     */
    public BaseOpCard checkCard(ArrayList<Integer> cardsList, ArrayList<Integer> card, int pos, int type) {
        Class cardType = DDZTypeAdapter.getInstance().obAdapterType(type);
        BasePKParameter parameter = new BasePKParameter();
        lastBaseOpCard.cardList.sort(BasePockerLogic.sorterBigToSmallHaveTrump);
        parameter.init(lastBaseOpCard.cardList, lastBaseOpCard.opCardType, lastBaseOpCard.compareValue, lastBaseOpCard.tripleNum, cardsList,new ArrayList<>(), card.size());
        return BasePkCardTypeFactory.getCardType(cardType).checkCardList(parameter);
    }

    /**
     * 检验获取剩余牌数
     *
     * @param roomPos
     * @return
     */
    private int checkAndReturnLeaveCard(DDZRoomPos roomPos) {
        int opPosCardLength;
        opPosCardLength = roomPos.privateCards.size();
        return opPosCardLength;
    }

    /**
     * 处理私有牌显示
     *
     * @param cardsList  牌
     * @param currentPos 自己的位置
     * @param showOps    显示的位置
     * @return
     */
    public ArrayList<Integer> resolveCardList(ArrayList<Integer> cardsList, int currentPos, int showOps) {
        ArrayList<Integer> cards = new ArrayList<>();
        for (Integer card : cardsList) {
            if (showOps == currentPos) {
                cards.add(card);
            } else {
                cards.add(0);
            }
        }
        return cards;
    }

    /**
     * 检测牌局是否结束
     *
     * @return
     */
    public boolean checkEndSet() {
        Optional<Integer> first = this.room.getRoomPosMgr().getPosList().stream().filter(n -> ((DDZRoomPos) n).privateCards.size() <= 0).map(n -> n.getPosID()).findFirst();
        first.ifPresent(n -> {
            this.m_bSetEnd = true;
            set.winPos = n;
        });
        return m_bSetEnd;
    }

    /**
     * 验证是否是自己的牌
     */
    public boolean checkIsMyCard(CDDZ_OpCard opCard) {
        DDZRoomPos roomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(opCard.pos);
        for (Integer byte1 : opCard.cardList) {
            if (!roomPos.privateCards.contains(byte1)) {
                return false;
            }
        }
        return true;
    }

    public List<Integer> getSameCardByNum(ArrayList<Integer> list, int num) {
        Map<Integer, List<Integer>> cardGroupMap = list.stream().collect(Collectors.groupingBy(p -> BasePocker.getCardValueEx(p)));
        return cardGroupMap.entrySet().stream().filter(m -> m.getValue().size() == num).map(n -> n.getKey()).collect(Collectors.toList());
    }

    /**
     * 判断炸弹是否正确且可出，并且比上一轮大
     *
     * @param opCardType 出牌类型
     * @param list       出牌列表
     * @return
     */
    public boolean isBombBigThanLast(int opCardType, ArrayList<Integer> list, int privateSize) {
        if (DDZ_CARD_TYPE.DDZ_CARD_TYPE_ZHADAN.value() != opCardType) {
            return false;
        }
        if (list.size() < 2) {
            return false;
        }
        Map<Integer, List<Integer>> cardGroupMap = list.stream().collect(Collectors.groupingBy(p -> BasePocker.getCardValueExx(p)));
        List<Integer> zhaValue = getSameCardByNum(list, 4);
        long jokerCount = cardGroupMap.entrySet().stream().filter(m -> m.getValue().size() == 2 && m.getKey() == JOKERVALUE).count();
        boolean haveFourZha = zhaValue != null && zhaValue.size() > 0;
        boolean isRocket = jokerCount > 0;
        if (!haveFourZha && !isRocket) {
            return false;
        }
        //上一轮最后出牌是炸弹
        if (lastOpCardType == DDZ_CARD_TYPE.DDZ_CARD_TYPE_ZHADAN.value()) {
            boolean lastIsAZha = lastCardList.stream().filter(m -> BasePocker.getCardValueExx(m) == JOKERVALUE).count() >= 2;
            List<Integer> lastZhaValue = getSameCardByNum(lastCardList, 4);
            if (lastIsAZha) {//上一轮是王炸炸，要不起
                return false;
            } else if (!isRocket && lastZhaValue.get(0) > zhaValue.get(0)) {//同类型炸弹,炸弹比对方小
                return false;
            }
        }
        return true;
    }

    /**
     * 当前轮结束，下一轮操作者设置
     *
     * @param isCalcEndTurn 是否允许过一圈
     */
    public void addOpPos(boolean isCalcEndTurn) {
        //设置下一回合等待操作的玩家
        for (int i = 0; i < this.room.getPlayerNum(); i++) {
            currentOpPos = (++currentOpPos) % this.room.getPlayerNum();
            DDZRoomPos tempRoomPos = (DDZRoomPos) this.room.getRoomPosMgr().getPosByPosID(currentOpPos);
            if (tempRoomPos.getPrivateCards().size() > 0) {
                break;
            }
        }
        this.set.startMS = CommTime.nowMS();
        //设置当局的等待的操作人
        this.set.setOpPos(currentOpPos);
        if (!isCalcEndTurn) return;

        //当前的操作人和最后一轮的操作人同一个，代表其他玩家都要不起
        if (currentOpPos == lastOpPos) {
            turnEnd = true;
        }
    }

    /**
     * @return currentOpPos
     */
    public int getOpPos() {
        return currentOpPos;
    }

    /**
     * @return lastOpPos
     */
    public int getLastOpPos() {
        return lastOpPos;
    }

    /**
     * @return lastOpCardType
     */
    public int getOpCardType() {
        return lastOpCardType;
    }

    /**
     * @return lastCardList
     */
    public ArrayList<Integer> getCardList() {
        return lastCardList;
    }

    /**
     * @return m_bSetEnd
     */
    public boolean isSetEnd() {
        return m_bSetEnd;
    }

    public String sysCardList(List<Integer> cardList) {
        StringBuilder stringBuilder = new StringBuilder("[");
        for (Integer card : cardList) {
            stringBuilder.append(getCardSystem(card) + ",");
        }
        stringBuilder.append("]");
        return stringBuilder.toString();
    }

    /**
     * 牌输出辅助器
     *
     * @param card
     * @return
     */
    public static String getCardSystem(int card) {
        int rank = card % 16;
        int color = card / 16;
        StringBuilder stringBuilder = new StringBuilder();
        switch (color) {
            case 0:
                stringBuilder.append("♦");
                break;
            case 1:
                stringBuilder.append("♣");
                break;
            case 2:
                stringBuilder.append("♥");
                break;
            case 3:
                stringBuilder.append("♠");
                break;
            case 4:
                stringBuilder.append("joker");
                break;
            default:
                stringBuilder.append("♦");
                break;
        }
        if (color != 4) {
            if (rank < 11) {
                stringBuilder.append(rank);
            } else {
                switch (rank) {
                    case 11:
                        stringBuilder.append("J");
                        break;
                    case 12:
                        stringBuilder.append("Q");
                        break;
                    case 13:
                        stringBuilder.append("K");
                        break;
                    case 14:
                        stringBuilder.append("A");
                        break;
                    case 15:
                        stringBuilder.append("2");
                        break;
                    default:
                        break;
                }
            }
        }
        return stringBuilder.toString();
    }

}
